package com.cg.nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

/**
 * public interface Channel extends Closeable
 * <p>
 * BIO stream是单向，Channel是双向通信，且可以异步读写
 * 实现类：
 * FileChannel
 * DatagramChannel
 * SocketChannel
 * ServerSocketChannel
 */
public class ChannelTest {

    public static void main(String[] args) throws IOException {
//        fileChannelWriteFile();
//        fileChannelReadFile();
//        fileChannelCopyFile();
//        scatterAndGathering();

        transferFromAndTransferTo();

    }

    private static void transferFromAndTransferTo() throws IOException {
        //原通道和目标通道的数据复制

        //transfer from
        FileInputStream fis = new FileInputStream("io-demo/src/main/java/com/cg/nio/data01.txt");
        FileChannel fisChannel = fis.getChannel();

        FileOutputStream fos = new FileOutputStream("io-demo/src/main/java/com/cg/nio/data03.txt");
        FileChannel fosChannel = fos.getChannel();
        fosChannel.transferFrom(fisChannel, fisChannel.position(), fisChannel.size());


        //transfer to
        FileInputStream fis2 = new FileInputStream("io-demo/src/main/java/com/cg/nio/data01.txt");
        FileChannel fisChannel2 = fis2.getChannel();

        FileOutputStream fos2 = new FileOutputStream("io-demo/src/main/java/com/cg/nio/data04.txt");
        FileChannel fosChannel2 = fos2.getChannel();
        fisChannel2.transferTo(fisChannel2.position(), fisChannel2.size(), fosChannel2);
    }

    private static void scatterAndGathering() throws IOException {
        //分散和聚集
        //分散读取(Scatter) 指把Channel通道的数据读入到多个缓冲区中去
        //聚集写入(Gathering) 指将多个Buffer中的数据聚集到Channel
        FileInputStream fis = new FileInputStream("io-demo/src/main/java/com/cg/nio/data01.txt");
        FileChannel fisChannel = fis.getChannel();

        FileOutputStream fos = new FileOutputStream("io-demo/src/main/java/com/cg/nio/data02.txt");
        FileChannel fosChannel = fos.getChannel();

        ByteBuffer allocate01 = ByteBuffer.allocate(2);
        ByteBuffer allocate02 = ByteBuffer.allocate(100);
        ByteBuffer[] byteBuffers = {allocate01, allocate02};

        fisChannel.read(byteBuffers);

        for (ByteBuffer byteBuffer : byteBuffers) {
            byteBuffer.flip();
            System.out.println(new String(byteBuffer.array(), 0, byteBuffer.remaining()));
        }

        fosChannel.write(byteBuffers);

        fis.close();
        fos.close();
        fisChannel.close();
        fosChannel.close();
    }

    private static void fileChannelCopyFile() throws IOException {
        FileInputStream fileInputStream = new FileInputStream("io-demo/src/main/java/com/cg/nio/20230919150021.png");
        FileOutputStream fileOutputStream = new FileOutputStream("io-demo/src/main/java/com/cg/nio/20230919150021_copy.png");

        FileChannel fis = fileInputStream.getChannel();
        FileChannel fos = fileOutputStream.getChannel();

        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while (true) {
            //每次循环清空缓冲区，使缓冲区重新读入数据
            buffer.clear();

            int read = fis.read(buffer);
            if (read == -1) {
                break;
            }

            //读模式切换为写模式
            buffer.flip();

            fos.write(buffer);
        }

        fis.close();
        fos.close();
        fileInputStream.close();
        fileOutputStream.close();
    }

    private static void fileChannelReadFile() throws IOException {
        //定义一个文件字节输入流
        FileInputStream fileInputStream = new FileInputStream("io-demo/src/main/java/com/cg/nio/data01.txt");
        //得到文件字节输入流的文件通道
        FileChannel channel = fileInputStream.getChannel();
        //定义一个缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        //读取数据到缓冲区
        channel.read(byteBuffer);
        byteBuffer.flip();

        String s = new String(byteBuffer.array(), 0, byteBuffer.remaining());
        System.out.println(s);
    }

    private static void fileChannelWriteFile() throws IOException {
        //字节输出流通向目标文件
        FileOutputStream fileOutputStream = new FileOutputStream("io-demo/src/main/java/com/cg/nio/data01.txt");
        //得到字节输出流对应的通道Channel
        FileChannel channel = fileOutputStream.getChannel();
        //分配缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put("cheyinbo_nio_test".getBytes());
        //把缓冲区切换为写出模式
        buffer.flip();
        channel.write(buffer);
        channel.close();
        fileOutputStream.close();
        System.out.println("写数据成功.....");
    }

}
